package com.cmc.cloud.cmclink.doc.util.sepcial;

import cn.hutool.core.collection.CollectionUtil;
import com.cmc.cloud.cmclink.doc.api.document.emums.CalculatePerEnum;
import com.cmc.cloud.cmclink.doc.api.document.emums.CurrencyEnum;
import com.cmc.cloud.cmclink.doc.constants.CommonConstants;
import com.cmc.cloud.cmclink.doc.constants.PatternSpecialCargoEmailConstants;
import com.cmc.cloud.cmclink.doc.constants.errorconstant.PartnerSpecialCargoEmailErrorCodeConstants;
import com.cmes.framework.ex.Assertion;
import com.google.gson.Gson;
import org.apache.tika.utils.StringUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * 通用方法
 *
 * @author dev89
 * @date 2025/07/14 14:42
 **/
public class CommonUtil {

    private static final Gson GSON = new Gson();

    /**
     * 含null值的比较方法
     *
     * @return int
     * @author dev89
     * @date 2025/07/14 14:44
     */
    public static <T extends Comparable<T>> int compareWithNull(T o1, T o2) {
        if (o1 == null && o2 == null) {
            return 0;
        } else if (o1 == null || o2 == null) {
            return o1 == null ? -1 : 1;
        } else {
            return o1.compareTo(o2);
        }
    }

    /**
     * 含null值的判断相等
     *
     * @param <T> T
     * @param o1 o1
     * @param o2 o2
     * @return boolean
     */
    public static <T> boolean checkEqual(T o1, T o2) {
        if (o1 == null && o2 == null) {
            return true;
        } else if (o1 == null || o2 == null) {
            return false;
        } else {
            return o1.equals(o2);
        }
    }

    /**
     * 判断是否有效邮箱
     *
     * @return boolean
     * @author dev89
     * @date 2025/07/15 13:31
     */
    public static boolean validEmail(String email) {
        Pattern pattern = Pattern.compile(CommonConstants.EMAIL_PATTERN);
        if (StringUtils.isEmpty(email)) {
            return false;
        }
        return pattern.matcher(email).matches();
    }

    public static void validEmails(String emailMix) {
        String[] emails = emailMix.split(PatternSpecialCargoEmailConstants.EMAIL_SPLIT_SEMICOLON);
        for (String email : emails) {
            if (!validEmail(email)) {
                Assertion.assertTrue(false).raise0(PartnerSpecialCargoEmailErrorCodeConstants.APPLY_EMAIL_ILLEGAL.getCode(), email);
            }
        }
    }

    /**
     * 判断是否有时间重叠
     *
     * @return java.lang.Boolean
     * @author dev89
     * @date 2025/07/24 16:53
     */
    public static Boolean dateOverlap(LocalDate srcStartDate, LocalDate srcEndDate, LocalDate trgStartDate,
        LocalDate trgEndDate) {
        return !(srcEndDate.isBefore(trgStartDate) || trgEndDate.isBefore(srcStartDate));
    }

    /**
     * 拼接关键字key
     *
     * @return java.lang.String
     * @author dev89
     * @date 2025/07/24 17:51
     */
    public static String buildKey(String param1, String param2, String param3) {
        StringBuilder key = new StringBuilder();
        if (param1 != null) {
            key.append(param1);
        }

        if (param2 != null) {
            key.append(param2);
        }

        if (param3 != null) {
            key.append(param3);
        }
        return key.toString();
    }

    /**
     * 获取两个列表的对称差集（A-B 和 B-A）
     *
     * @param listA 第一个列表
     * @param listB 第二个列表
     * @return 包含两个元素的数组，第一个元素是A-B，第二个元素是B-A
     */
    public static List<Long>[] getSymmetricDifference(List<Long> listA, List<Long> listB) {
        if (CollectionUtil.isEmpty(listA)) {
            listA = new ArrayList<>();
        }
        if (CollectionUtil.isEmpty(listB)) {
            listB = new ArrayList<>();
        }
        Set<Long> setA = new HashSet<>(listA);
        Set<Long> setB = new HashSet<>(listB);

        // A-B：在A中但不在B中的元素
        List<Long> onlyInA = listA.stream().filter(e -> !setB.contains(e)).collect(Collectors.toList());

        // B-A：在B中但不在A中的元素
        List<Long> onlyInB = listB.stream().filter(e -> !setA.contains(e)).collect(Collectors.toList());

        return new List[] {onlyInA, onlyInB};
    }

    /**
     * 计算乘积，并保留2位小数，四舍五入
     *
     * @param v1 乘数
     * @param v2 被乘数
     * @return java.math.BigDecimal
     */
    public static BigDecimal decimalMulHalfUp(BigDecimal v1, BigDecimal v2) {
        return decimalMulHalfUp(v1, v2, "");
    }

    /**
     * 计算乘积，日本货币保留整数，其它保留2位小数
     *
     * @param v1 费率
     * @param v2 数量
     * @param currency 货币种类
     * @return java.math.BigDecimal
     */
    public static BigDecimal decimalMulHalfUp(BigDecimal v1, BigDecimal v2, String currency) {
        return decimalMulHalfUp(v1, v2, currency, CalculatePerEnum.CNTR.getValue());
    }

    /**
     * 计算乘积，日本货币保留整数，其它保留2位小数
     *
     * @param v1 费率
     * @param v2 数量
     * @param currency 货币种类
     * @return java.math.BigDecimal
     */
    public static BigDecimal decimalMulHalfUp(BigDecimal v1, BigDecimal v2, String currency, String per) {
        BigDecimal result;
        int scale;
        if (CurrencyEnum.JPY.getValue().equalsIgnoreCase(currency)) {
            scale = 0;
        } else {
            scale = 4;
        }
        if (CalculatePerEnum.CBM.getValue().equals(per)) {
            result = v1.multiply(v2).setScale(scale, RoundingMode.HALF_UP);
        } else {
            result = v1.setScale(scale, RoundingMode.HALF_UP).multiply(v2).setScale(scale, RoundingMode.HALF_UP);
        }
        return result;
    }

    /**
     * 深拷贝
     *
     * @param <T> 参数
     * @param clazz class
     * @return T
     */
    public static <T> T deepCopy(T obj, Class<T> clazz) {
        // 对象转JSON字符串
        String json = GSON.toJson(obj);
        // JSON字符串转新对象
        return GSON.fromJson(json, clazz);
    }

    /**
     * 如果当前时间已超过今年年底，计算到明年年底的时间
     *
     * @return long
     */
    public static long calculateMillisToEndOfYear() {
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime endOfYear = LocalDateTime.of(now.getYear(), 12, 31, 23, 59, 59, 999_999_999);
        // 如果当前时间已超过今年年底，计算到明年年底的时间
        if (now.isAfter(endOfYear)) {
            endOfYear = endOfYear.plusYears(1);
        }
        return Duration.between(now, endOfYear).toMillis();
    }

    /**
     * 计算当前时间是否在日期之内(before或after方法不精确)
     *
     * @param beginDate 开始时间 YYYY-MM-DD
     * @param endDate 结束时间 YYYY-MM-DD
     * @return boolean
     */
    public static boolean isIsBetween(Date beginDate, Date endDate) {
        Date currentTime = new Date();
        boolean isBetween = false;
        if (beginDate != null && endDate != null) {
            long beginTime = beginDate.getTime();
            long endTime = endDate.getTime();
            long currentTimeMillis = currentTime.getTime();
            isBetween = currentTimeMillis >= beginTime && currentTimeMillis <= endTime;
        }
        return isBetween;
    }
}
